﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Linq.Expressions;
using System.Runtime.Serialization;
using Norm;
using Norm.Commands.Modifiers;

namespace StudyTracker.Domain.Entities
{
	[DataContract]
	public class MongoDocument<T>
	{
		public static void Delete(Expression<Func<T, bool>> expression)
		{
			using (IMongo session = CreateSession())
			{
				IQueryable<T> entities = session.GetCollection<T>().AsQueryable().Where(expression);

				foreach (T entity in entities)
				{
					session.GetCollection<T>().Delete(entity);
				}
			}
		}

		public static void Update<X>(X matchDocument, Action<IModifierExpression<T>> action, bool updateMultiple, bool upsert)
		{
			using (IMongo session = CreateSession())
			{
				session.GetCollection<T>().Update(matchDocument, action, updateMultiple, upsert);
			}
		}

		public static IEnumerable<T> Find<U>(U template)
		{
			IEnumerable<T> collection;

			using (IMongo session = CreateSession())
			{
				collection = session.GetCollection<T>().Find(template);
			}

			return collection;
		}

		public static IEnumerable<T> Find<U, O>(U template, O orderBy, int limit, int skip)
		{
			IEnumerable<T> collection;

			using (IMongo session = CreateSession())
			{
				collection = session.GetCollection<T>().Find(template, orderBy, limit, skip);
			}

			return collection;
		}

		public static void DeleteAll()
		{
			using (IMongo session = CreateSession())
			{
				session.GetCollection<T>().Delete(new { });
			}
		}

		public static List<T> FindAll()
		{
			List<T> list;

			using (IMongo mongo = CreateSession())
			{
				list = mongo.GetCollection<T>().AsQueryable().ToList();
			}

			return list;
		}

		public static List<T> Find(Expression<Func<T, bool>> expression)
		{
			List<T> list;

			using (IMongo mongo = CreateSession())
			{
				list = mongo.GetCollection<T>().AsQueryable().Where(expression).ToList();
			}

			return list;
		}

		public static T Single()
		{
			T single;

			using (IMongo mongo = CreateSession())
			{
				single = mongo.GetCollection<T>().AsQueryable().Single();
			}

			return single;
		}

		public static void Save(T entity)
		{
			using (IMongo session = CreateSession())
			{
				session.GetCollection<T>().Save(entity);
			}
		}

		public static void Save(IEnumerable<T> entities)
		{
			if (entities == null) return;
			foreach (T entity in entities)
			{
				Save(entity);
			}
		}

		private static IMongo CreateSession()
		{
			return Mongo.Create(ConfigurationManager.ConnectionStrings["MongoDb"].ConnectionString);
		}
	}
}